/**
 * Created by zaranengap on 2017/9/1.
 */
import axios from 'axios';
import qs from 'qs'
import config from 'config';
import { message } from 'antd';
import configureStore from 'stores';
import {setAuthToken} from "actions/main";
import {getToken, removeToken, messages, getUrlSearchParams} from 'share/common'
import routeService from 'routes/route.service';
import loginService from 'containers/login/login.service';
import ravenHttpError from 'share/sentry';

const realmId = config.realmIds[location.host] || config.realmId;
/**
 * 检查是否token过期
 * @param response    该请求的response
 * @param needRefresh    是否需要刷新token，如果是登录操作则不需要
 * @param url    原请求路径，将在刷新成功后再次请求
 * @param params    原请求参数
 * @param header    原请求头
 * @param method    原请求方法
 * @return {*}
 */
//当不断重复发生401响应的时候，请求5个就去登录
function checkStatus(response, needRefresh, url, params, header, method) {
  if (!response) {
    throw new Error('未知错误')
  }
  if(window.location.href.indexOf("source=dingding") !== -1){
    if(response.status !== 200){
      throw response;
    }
  }
  if (response.status >= 200 && response.status < 300) {
    return Promise.resolve(response);
  } else {
    // 延迟执行，异常搜集，防止因为sentry报错导致程序不能正常执行
    setTimeout(()=>{
      ravenHttpError(url, response);
    }, 0);
    if(response.status === 401) {
      console.log(response);
      let requestCount = localStorage.getItem('hly.requestCount');
      if(!requestCount){
        localStorage.setItem('hly.requestCount', '0');
        requestCount = 0;
      } else {
        try {
          requestCount = JSON.parse(requestCount)
        } catch(e) {
          requestCount = 0;
        }
      }
      requestCount++;
      localStorage.setItem('hly.requestCount', requestCount);
      if(requestCount >= 5){
        localStorage.setItem('hly.error', messages("common.error"));
        removeToken();
        localStorage.setItem('hly.requestCount', '0');
        location.href = '/';
      } else {
        if(needRefresh){
          return httpFetch.refreshToken().then(() => {
            return new Promise((resolve) => {
              httpFetch[method.toLowerCase()](url, params, header).then((res) => {
                localStorage.setItem('hly.requestCount', '0');
                resolve(res)
              });
            })
          });
        } else {
          localStorage.setItem('hly.error', messages("common.error"));
          removeToken();
          localStorage.setItem('hly.requestCount', '0');
          location.href = '/';
        }
      }
    }else if(response.status === 400 && url.indexOf('oauth/token') > -1){
      // bug 40079
      message.warn(messages('components.key1016')/*登录过期*/);
      location.href = '/';
    }else {
      let error = new Error(response.statusText);
      error.response = response;
      throw error;
    }
  }
}
//获取登录的数据
function getLoginFormData(username, password, loginType, client_name, loginId, cryptType, tenantId) {
  localStorage.removeItem('isAccountLogin');
  let dataCommon = {
    grant_type: 'password',
  };
  let data = {};
  switch (loginType){
    case 'ssoDirect':{
      // 企业单点登录 2
      data = {
        scope: 'read write',
        username,
        password,
        loginType,
        client_name,
        client_id: 'ArtemisWeb',
        client_secret: 'nLCnwdIhizWbykHyuZM6TpQDd7KwK9IXDK8LGsa7SOW',
        cryptType
      };
      break;
    }
    case 'sso':// 企业单点登录 1
    case 'app':// app 扫描登录
    case 'wxweb':// 企业微信登录
    case 'public_install':// 企业微信登录
    case 'custom_install':// 企业微信登录
    case 'authorizationCode':{
      //授权码直接登录
      data = {
        scope: 'read write',
        username,
        password,
        loginType,
        loginId,
        client_id: 'ArtemisWeb',
        client_secret: 'nLCnwdIhizWbykHyuZM6TpQDd7KwK9IXDK8LGsa7SOW',
      };
      break;
    }
    case 'privateSso':{
      // 私有化单点登录改造 by ting.zhang
      data = {
        username,
        password,
        loginType,
        client_id: 'ArtemisWeb',
        client_secret: 'nLCnwdIhizWbykHyuZM6TpQDd7KwK9IXDK8LGsa7SOW'
      };
      break;
    }
    case 'bossSso':{
        data = {
          username,
          password,
          loginType,
          client_id: 'ArtemisWeb',
          client_secret: 'nLCnwdIhizWbykHyuZM6TpQDd7KwK9IXDK8LGsa7SOW'
        };
        break;
    }
    case 'maintenanceSso':{
      data = {
        username,
        password,
        loginType,
        client_id: 'ArtemisWeb',
        client_secret: 'nLCnwdIhizWbykHyuZM6TpQDd7KwK9IXDK8LGsa7SOW'
      };
      break;
    }
    case 'freeTrial':{
      //试用
      data = {
        scope: 'write',
        username,
        loginType,
        loginId,
        client_id: 'ArtemisWeb',
        client_secret: 'nLCnwdIhizWbykHyuZM6TpQDd7KwK9IXDK8LGsa7SOW'
      };
      break;
    }
    case 'operation':{
      //运营系统进来
      data = {
        username,
        loginType,
        tenantId,
        grant_type: "password",
        scope: 'write',
        client_id: "ArtemisOperation",
        client_secret: "nLCnwdIhizWbykHyuZM6TpQDd7KwK9IXDK8LGsa7SOW"
      };
      break;
    }
    default:{
      //账号登录
      localStorage.setItem("isAccountLogin",true);
      let publicKey = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC4Ma89QEzyu7Oa3Zo0PDXyp/FPetLhvrr86uBC/nMlpJs2sOmusG6cYwPRfMR9aoFNYYy61xAbyHonJ9mvdXKCrrv+h3qlS7yjHCvPoyzgJFeJKy7pNCm7drEvpRMC2jMUvn9XgBBhH5aKY+7iZ5JNZYC8405aqUh71bsFIAtD1QIDAQAB";
      let _password = encodeURIComponent(loginService.encrypt(password, publicKey));
      /*
     * 新增参数cryptType
     *cryptType=1时，后端通过AES进行解密
     *cryptType=2时，后端通过CBC进行解密
     *cryptType=2.1 - type=web
     *cryptType=2.2 - type=native
     *cryptType=3时，后端根据RSA进行解密
     *当encrypt_type为空时，兼容原登录解密方式，根据客户端以及特殊登录分别解密
     *前端将密码进行对应加密方式加密并传加密参数至后端。
     * */
      data = {
        scope: 'read write',
        username,
        cryptType: "3",//告诉后端当前的加密方式
        password:_password,
        "x-helios-client": 'web',
        client_id: 'ArtemisWeb',
        client_secret: 'nLCnwdIhizWbykHyuZM6TpQDd7KwK9IXDK8LGsa7SOW'
      };
      break;
    }
  }
  let dataCom = Object.assign(data,dataCommon);
  // let ieFormData = function ieFormData() {
  //   if (window.FormData === undefined) {
  //     this.processData = true;
  //     this.contentType = 'application/x-www-form-urlencoded';
  //     this.append = function (name, value) {
  //       this[name] = value === undefined ? "" : value;
  //       return true;
  //     }
  //   }
  //   else {
  //     let formdata = new FormData();
  //     formdata.processData = false;
  //     formdata.contentType = false;
  //     return formdata;
  //   }
  // };
  // const formData = new ieFormData();
  // Object.keys(dataCom).map(key => {
  //   formData.append(key, dataCom[key]);
  // });
  return dataCom;
}
const httpFetch = {

  unsafe: {},

  /**
   * 刷新token
   * @return {Promise.<TResult>}
   */
  refreshToken: function(){
    let refreshParams = `client_id=ArtemisWeb&client_secret=nLCnwdIhizWbykHyuZM6TpQDd7KwK9IXDK8LGsa7SOW&refresh_token=${configureStore.store.getState().main.authToken.refresh_token}&grant_type=refresh_token`;
    return axios(encodeURI(`${config.baseUrl}/oauth/token?${refreshParams}`),{
      method: 'POST',
      headers: {
        'x-helios-client': 'web',
        'Content-Type': 'application/x-www-form-urlencoded',
        'Authorization': 'Bearer ' + configureStore.store.getState().main.authToken.access_token
      }
    }).then(checkStatus).catch(e => {
      message.error(configureStore.store.getState().main.language.messages['login.token.expired']);
      configureStore.store.dispatch(setAuthToken(null))
      removeToken();
      location.href = '/';
    }).then(response => {
      let expiredAt = new Date();
      let token = response.data;
      expiredAt.setSeconds(expiredAt.getSeconds() + token.expires_in);
      token.expires_at = expiredAt.getTime();
      configureStore.store.dispatch(setAuthToken(token))
      localStorage.getItem('hly.token') && localStorage.setItem('hly.token', JSON.stringify(token));
      sessionStorage.getItem('hly.token') && sessionStorage.setItem('hly.token', JSON.stringify(token));
    })
  },


  /**
   * 登录，不需刷新token
   * @param username    用户名
   * @param password    密码
   * @param loginType   登录类型-单点登录加sso，ssoDirect
   * @param client_name 当登录方式是client_name，需要传入这个参数
   * @return {*|Promise.<TResult>}
   */
  login: function(username, password, loginType, client_name, loginId, cryptType, tenantId){
    let formData = getLoginFormData(username, password, loginType, client_name, loginId, cryptType, tenantId);
    let url = encodeURI(`${config.baseUrl}/oauth/token?`);
    Object.keys(formData).map((key, index) => {
      index !== 0 && (url += '&');
      url += `${key}=${formData[key]}`;
    });
    let header = {
        'x-helios-client': 'web',
        'Content-Type': 'application/x-www-form-urlencoded',
        'Accept': 'application/json',
        // 'Authorization': 'Basic QXJ0ZW1pc1dlYjpuTENud2RJaGl6V2J5a0h5dVpNNlRwUURkN0t3SzlJWERLOExHc2E3U09X'
      };
    //如果是钉钉单点登录进来
    let param = "";
    if(username && username.ddsso){
      let {params, headers, useAuthService} = username;
      if(useAuthService){
        url= '/auth/oauth/token'
      }
      param = params;
      header =  headers;
    }
    return axios({
      url,
      method: 'POST',
      headers: header,
      params: param,
      // data: formData
    }).then(checkStatus).catch(error => {
      // 为麦当劳pc端portal失效做的跳转机制
      console.log(error.response.data.error_description)
      if(error.response && error.response.data && error.response.data.error_description == 'portal.token.error') {
        if(config.appEnv == 'dist') {
          location.href = 'http://portal.mcd.com.cn';
        }else {
          location.href = 'http://portalstg.mcd.com.cn';
        }
      }
      else if(error.response && error.response.data && error.response.data.error_description == 'vendor.not.found') {
        message.error('您尚未建立Vendor，请联系AC.Support@cn.mcd.com创建后再使用本系统');
      }

    }).then((response)=>{
      if(loginType === "wxweb" || loginType === "custom_install" || loginType === "public_install"){
        //是来自企业微信登录的
        sessionStorage.setItem('user_from_wechat', true);
      }else {
        sessionStorage.removeItem('user_from_wechat');
      }
      if(username && !username.ddsso){
        sessionStorage.setItem('loginAccount', username);
      }
      let expiredAt = new Date();
      let token = response.data;
      expiredAt.setSeconds(expiredAt.getSeconds() + token.expires_in);
      token.expires_at = expiredAt.getTime();
      configureStore.store.dispatch(setAuthToken(token));
      localStorage.setItem('hly.token', JSON.stringify(token));
    });
  },
};

//请求入口方法
let methodList = ['get', 'post', 'put', 'delete', 'patch'];
methodList.map(method => {
  httpFetch.unsafe[method] = function(url, params = {}, header, options = {}, needTenant = true) {
    //在某些菜单下，集团模式时不传 roleType=TENANT
    let specialMenus = ["customer-info-maintenance", "supplier-maintain"];
    let bool = specialMenus.some(item => window.location.href.indexOf(item) !== -1);
    let tenantMode = configureStore.store.getState().main.tenantMode;
    let user = configureStore.store.getState().login.user;
    if(url.indexOf("api/authorization/policy/user/permission") === -1) {
      if ((!user.enableNewPermission  || (user.enableNewPermission && user.hasTenantRole  && !bool))
        && needTenant && tenantMode) {
        if (url.indexOf("api/public/getGMVPOfficer") === -1 && url.indexOf("api/public/getC5People") === -1 && url.indexOf("api/public/getRestaurantPeople") === -1 && url.indexOf("api/public/getDOPeople") === -1 && url.indexOf("api/quato/displayRemainingQuota") === -1 && url.indexOf('api/public/getAll') === -1) {
          if (url.indexOf('?') >= 0) {
            if (url.indexOf('roleType=TENANT') < 0 && !params.roleType) {
              url += '&roleType=TENANT'
            }
          } else {
            if (method === 'get' || method === 'delete') {
              if (!params.roleType) {
                params.roleType = 'TENANT';
              }
            } else {
              url += '?roleType=TENANT'
            }
          }
        }
      }
    }
    let storeToken = configureStore.store.getState().main.authToken.access_token;
    if(storeToken &&
      getToken() &&
      storeToken !== JSON.parse(getToken()).access_token){
      window.location.reload();
      return;
    }
    let option = {
      url: url,
      method: method.toUpperCase(),
      mode: 'cors',
      headers: header,
      data: params,
      params:(method === 'get' || method === 'delete') ? params : undefined,
      //序列化get模式下的数组为repeat形式
      paramsSerializer: function(params) {
        return qs.stringify(params, {arrayFormat: 'repeat'})
      }
    };
    return axios(url, Object.assign({}, options, option))
      .catch(e => checkStatus(e.response, true, url, params, header, method.toUpperCase()))
  };

  httpFetch[method] = function(...args) {
    return httpFetch.unsafe[method](...args).then(res => {
      if(res && res.data && typeof res.data === 'object' && !(args[3] && args[3].responseType === 'arraybuffer')) {
        return {
          ...res,
          data: JSON.parse(JSON.stringify(res.data).replace(/</g, '﹤').replace(/>/g, '﹥'))
        }
      } else {
        return res;
      }
    })
  };

});

//配置一个拦截器
//只有有请求，或者响应要拦截就通过这种方式
// http请求拦截器
axios.interceptors.request.use(function (config) {
  //登录接口不要加
  if (config.url && config.url.indexOf('/oauth/token') > -1 || config.url && config.url.indexOf('dingtalk') > -1) {
    return config;
  }
  let header = config.headers ? config.headers : {};
  header["x-helios-client"] = 'react web';

  //新权限控制，header 中加菜单id，后端控制权限
  let rsId = routeService.getResourceIdByMenu();
  if(rsId){
    header["resourceId"] = rsId;
  }
  header["x-helios-router"] = window.location.pathname;
  header.language = configureStore.store.getState().main.language.code.toLowerCase();

  // 麦当劳供应商接口特殊处理 by ting.zhang
  const curl = config.url;
  if(curl.indexOf('vendor-data-service') > -1 || curl.indexOf('vendor-info-service') > -1) {
    // header.Authorization = "Bearer " + configureStore.store.getState().main.publicToken;
    let paramsObj = config.params ? config.params : {};
    paramsObj['realmId'] = realmId;
    config.params = paramsObj;
  }else {
    // header.Authorization = "Bearer " + configureStore.store.getState().main.authToken.access_token;
  }
  header.Authorization = "Bearer " + configureStore.store.getState().main.authToken.access_token;

  config.headers = header;
  // 处理请求之前的配置
  return config;
},  error=> {
  // 请求失败的处理
  return Promise.reject(error);
});

// http响应拦截器
axios.interceptors.response.use(data => {
  return fixTask13509(data);
}, error => {
  return Promise.reject(error)
});

/*
* 任务id 13509  需求id 4208
* 系统银行与公司银行code一样，导致编辑的时候，弹窗两条数据都被选中。
* 为什么不 id 做key？ 因为公司银行，之前没有存 银行id，只是存了银行的code，银行名称等字段。
* 现在后端加一个 bankType 字段，需要与 bankCode 一起，当做key,在list-selector组件不方便处理，这里添加一个字段
*
* Comment by ZaraNengap:
* 话说这样的逻辑写到对应业务service里不是更好吗
* 拦截器不应该做对应业务数据处理的工作
* 应该是更加统一处理一些格式、模块结果的地方
* 现在这样每个接口都要走一遍这个判断，而且这个文件也不纯了
*
* 这个接口在很多模块都有（凡是用到选择银行弹窗的模块）
* 我加在哪一个文件呢？在没有更好的解决方案出现，占时放这里
*
* */
function fixTask13509(data){
  if(data.config.url.match('/api/bank/infos/search') && data.data && data.data.length){
    data.data.map((item)=>{
      item.bankTypeBankCode = item.bankType + item.bankCode;
    })
  }
  return data;
}



export default httpFetch

